/** \file translatorHelper.cpp
* A helper class for translating a ProgGraph into g-mini Graph or vise versa
*/

#include "translatorHelper.h"
#include <string>
#include <iostream>

using namespace std;


NodeTypeInterface * ForwardGraphTranslator::getEquivalentDecorator(Node * node)
{
	NodeType type=node->t;
	switch(type)
	{
	case ARRAY_TYPE:
		return new DecoratedArrayNodeType(getEquivalentDecorator(our_graph->getChild(node,OF_EDGE)));
	case PAIR_TYPE:
		return new DecoratedPairNodeType( getEquivalentDecorator(our_graph->getChild(node,LEFT ))
							   , getEquivalentDecorator(our_graph->getChild(node,RIGHT)) );
	case INT_TYPE:
	case BOOL_TYPE:
		return new SimpleNodeType(type);
	case ARITH_OP:
	case BOOL_OP:
	case BOOL_COMP:
	case ERROR_NODE:
		return new TaggedSimpleNodeType(type,node->info);
	case START: /*statements*/
	case EMPTY_ST:
	case ASSIGN_ST:
	case DECL:
	case IF_ST:
	case WHILE_ST:
	case OUTPUT_ST:
	case ARRAY_OP: /*array and pair operators*/
	case PAIR_OP:
	case ID_NAME: /*identifier*/
	case INT_VAL: /*constants*/
	case BOOL_VAL:
		return new SimpleNodeType(type);
	default:
		throw -1;
	}
}
NewGraph::ProgNode * ForwardGraphTranslator::createNode(Node * node)
{
	NodeTypeInterface * decorator=getEquivalentDecorator(node);
	NodeType type=node->t;
	switch (type)
	{
	case ARRAY_TYPE:
	case PAIR_TYPE:
	case INT_TYPE:
	case BOOL_TYPE:
	case ID_NAME: /*identifier*/
		cout<<"types or variables not resolved here!!!\n";
		return NULL; //types must not be resolved here
	case ARITH_OP: /*expression operators and comparators*/
	case BOOL_OP:
	case BOOL_COMP:
	case ARRAY_OP: /*array and pair operators*/
	case PAIR_OP:
		return new NewGraph::ProgExpr(decorator);
	case ERROR_NODE:
	case START: /*statements*/
	case EMPTY_ST:
	case ASSIGN_ST:
	case DECL:
	case IF_ST:
	case WHILE_ST:
	case OUTPUT_ST:
		return new NewGraph::ProgStmt(decorator);
	case INT_VAL: /*constants*/
	case BOOL_VAL:
		return new NewGraph::ProgLit(decorator, node->info);
	default:
		throw -1;
	}
}

void ForwardGraphTranslator::translateAndInsert(Node* node)
{
	NewGraph::ProgNode * n=getCorrespondingNode(node);
	if (n!=NULL)
		return;
	switch(node->t)
	{
	case ID_NAME:
		{
			Node * parent=our_graph->getParent(node);
			if (parent->t==DECL)
			{
				Node * varType=our_graph->getChild(parent,VARTYPE);
				NodeTypeInterface * decorator=getEquivalentDecorator(varType);
				new_graph->varMap.insert(VariablesPair(node->info,VariableInfo(decorator)));
				NewGraph::ProgVar * v = new NewGraph::ProgVar(decorator, node->info);
				new_graph->addNode(v);
				corrMap.insert(NodesCorrespondencePair(node,v));
			}
			else
			{
				string varName=node->info;
				NodeTypeInterface * decorator=getVariableDecorator(varName);
				NewGraph::ProgVar * v = new NewGraph::ProgVar(decorator,varName);
				new_graph->addNode(v);
				corrMap.insert(NodesCorrespondencePair(node,v));
			}
			break;
		}
	case ARRAY_TYPE:
	case PAIR_TYPE:
	case INT_TYPE:
	case BOOL_TYPE:
		break; //do nothing, already done in declaration
	default:
		insertNode(node);

	}
}
void ForwardGraphTranslator::translateAndInsert(Edge* edge)
{
	NewGraph::ProgNode * n1=getCorrespondingNode(edge->start),
					   * n2=getCorrespondingNode(edge->end);
	if (n2==NULL)
	{
		translateAndInsert(edge->end);
		n2=getCorrespondingNode(edge->end);
	}
	NodeType n=edge->end->t;
	if ( n!=ARRAY_TYPE && n!= PAIR_TYPE && n!= INT_TYPE && n!= BOOL_TYPE )//dont link edges for types, translated to decorator
		new_graph->addEdge(n1,n2, edge->label);
}

Node * BackwardGraphTranslator::translateAndInsert(NewGraph::ProgNode * n)
{
	Node * node=getCorrespondingNode(n);
	if (node!=NULL)
		return node;

	NodeType t = n->data->type;

	if(n->type()==NewGraph::Literal)
	{
		node=new Node(t,((NewGraph::ProgLit*)n)->value);
		insertNode(n, node);

	} else if (n->type()==NewGraph::Expression)
	{
		if(t == ARRAY_OP || t == PAIR_OP)
		{
			node=new Node(t,"");
		}
		else
		{
			string op = n->data->getAdditionalTag();
			node=new Node(t, op);
		}
		insertNode(n, node);

	}
	else if(n->type()==NewGraph::Statement)
	{
		if(n->data->toString() == "Start Virtual Node")
		{
			node=new Node(t,"Start");
			new_graph->setRoot(node);
		}
		else
			node=new Node(t,"");
		insertNode(n, node);
	}
	return node;
}

void BackwardGraphTranslator::translateAndInsert(NewGraph::ProgEdge * edge)
{
	Node * n1=getCorrespondingNode(&edge->from);
	if(edge->to.type()!=NewGraph::Variable)
	{
		Node * n2=translateAndInsert(&edge->to);
		new_graph->createEdge(n1, n2, edge->weight);
	}
	else
	{
		NewGraph::ProgVar& var=(NewGraph::ProgVar&)(edge->to);
		Node * n3=new Node(ID_NAME,var.name);
		insertNode(&(edge->to), n3);
		if(n1->t == DECL)
		{
			// Create 2 nodes one for Variable Type One for Variable Name

			new_graph->createEdge(n1, n3, VARNAME);

			Node * n4 = createTypeBranch((edge->to).data);
			new_graph->createEdge(n1, n4, VARTYPE);
			//Create More Nodes and More Edges for COmposite Types
		} else 	{
			new_graph->createEdge(n1, n3, edge->weight);
		}
	}
}

Node * BackwardGraphTranslator::createTypeBranch(NodeTypeInterface * dec) {

	NodeType type=dec->type;
	switch(type)
	{
	case INT_TYPE:
		return new Node(INT_TYPE, "Int");
	case BOOL_TYPE:
		return new Node(BOOL_TYPE, "Bool");
	case ARRAY_TYPE:
		{
			Node * array_node=new Node(ARRAY_TYPE, "Array");
			Node * subtree=createTypeBranch(dec->getSubType1());
			new_graph->createEdge(array_node, subtree, OF_EDGE);
			return array_node;
		}
	case PAIR_TYPE:
		{
			Node * pair_node=new Node(PAIR_TYPE, "Pair");
			Node * subtree1=createTypeBranch(dec->getSubType1());
			Node * subtree2=createTypeBranch(dec->getSubType2());
			new_graph->createEdge(pair_node, subtree1, LEFT);
			new_graph->createEdge(pair_node, subtree2, RIGHT);
			return pair_node;
		}
	default:
		throw -1;
	}
}
